iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
Web 3

Web3 X 公共財系列 第 28

Day 28 - PCO-2: the space / thisartworkisalwaysonsale / fxhash ticket

  • 分享至 

  • xImage
  •  

the space

spaceDAO文章集
Github contract
由三個Interface + 三個實作 及 一個token合約組成,包含

contract SpaceToken is ERC20 {
    constructor(
        address incentives,
        uint256 incentivesTokens,
        address treasury,
        uint256 treasuryTokens,
        address team,
        uint256 teamTokens,
        address lp,
        uint256 lpTokens
    ) ERC20("The Space", "SPACE") {
        // Early Incentives
        _mint(incentives, incentivesTokens * (10**uint256(decimals())));

        // Community Treasury
        _mint(treasury, treasuryTokens * (10**uint256(decimals())));

        // Team
        _mint(team, teamTokens * (10**uint256(decimals())));

        // Liquidity Pool
        _mint(lp, lpTokens * (10**uint256(decimals())));
    }
}

IACLManager 用於管理_The Space_市場的ACLManager合約的介面, 每個角色都可以授予一個地址,role管理。
所有可用的角色都在Role列舉(ENUM)中定義 [aclManager,marketAdmin,treasuryAdmin]

IACLManager {
    //////////////////////////////
    /// 錯誤類型
    //////////////////////////////

    error RoleRequired(Role role);
    error Forbidden();
    error ZeroAddress();

    //////////////////////////////
    /// 事件類型
    //////////////////////////////

    event RoleTransferred(Role indexed role, address indexed prevAccount, address indexed newAccount);

    /**
     * aclManager: 負責分配和撤銷其他地址的角色
     * marketAdmin: 負責更新配置,例如稅率或國庫率。
     * treasuryAdmin: 負責從合約中提取國庫。
     */
    enum Role {
        aclManager,
        marketAdmin,
        treasuryAdmin
    }

    function hasRole(Role role, address account) external returns (bool);

    /**
     * 將角色授予帳戶(`newAccount`)。
     * @dev 不能授予`Role.aclManager`。
     *
     * @dev 存取:只有`Role.aclManager`。
     * @dev 拋出:`RoleRequired`、`Forbidden`或`ZeroAddress`錯誤。
     */
    function grantRole(Role role, address newAccount) external;

    /**
     * 將角色轉移到新帳戶(`newAccount`)。
     * @dev 存取:只有當前角色地址。
     * @dev 拋出:`RoleRequired`或`ZeroAddress`錯誤。
     */
    function transferRole(Role role, address newAccount) external;

    /**
     * 從角色地址撤銷角色。
     * @dev `Role.aclManager`不能被撤銷。
     *
     * @dev 存取:只有當前角色地址。
     * @dev 拋出:`RoleRequired`或`Forbidden`錯誤。
     */
    function renounceRole(Role role) external;
}

ITheSpace 遊戲本身
the space 是由去中心化自治組織 (DAO) 所擁有的像素空間,其中成員可以將像素代幣化、擁有、交易和著色。
Pixel 像素被代幣化為 ERC721 代幣,並根據 Harberger 稅進行交易,而成員根據他們擁有的像素份額接收股息。

交易

  • 用戶在開始之前需要在貨幣合約上調用approve。如果沒有足夠的許可稅,則相應的資產將被默認。
  • 用戶購買像素:調用bid()
  • 用戶設置像素價格:調用setPrice()

此合約包含市場的邏輯,同時從 {TheSpaceRegistry} 讀取並寫入,這是存儲合約。
此合約擁有一個 {TheSpaceRegistry} 合約用於存儲,並可以通過將所有權轉移到新的實現合約來更新。

ITheSpace {
    //////////////////////////////
    /// 錯誤類型
    //////////////////////////////
    error PriceTooLow();
    error PriceTooHigh(uint256 maxPrice);
    error Unauthorized();
    * @dev 給定的代幣不存在,需要首先通過出價來鑄造。
    error TokenNotExists();

    //////////////////////////////
    /// 升級性 Upgradability
    //////////////////////////////

    /**
     * 將邏輯合約切換到另一個。
     *
     * @dev 存取:只有 `Role.aclManager`。
     * @dev 拋出:`RoleRequired` 錯誤。
     *
     * @param newImplementation 新邏輯合約的地址。
     */
    函數 upgradeTo(address newImplementation) external;

    //////////////////////////////
    /// 配置 / 管理員 Configuration / Admin
    //////////////////////////////
    function setTotalSupply(uint256 totalSupply_) external;

    /**
     *  更新當前的稅收配置。
     *
     * 存取:只有 `Role.marketAdmin`。
     * 發出:`Config` 事件。
     * 拋出:`RoleRequired` 錯誤。
     *
     */
    function setTaxConfig(ITheSpaceRegistry.ConfigOptions option_, uint256 value_) external;

    /**
     *  提取所有可用的國庫。
     *
     * 存取:只有 `Role.treasuryAdmin`。
     * 拋出:`RoleRequired` 錯誤。
     *
     * @param to_ DAO 國庫的地址。
     */
    function withdrawTreasury(address to_) external;

    /**
     * 存取:只有 `Role.aclManager`。
     * 拋出:`RoleRequired` 錯誤。
     */
    function setTokenImageURI(string memory uri_) external;
    
    /////////////////////////////
    /// Pixel 像素
    //////////////////////////////

    function getPixel(uint256 tokenId_) external view returns (ITheSpaceRegistry.Pixel memory pixel);

    /**
     * 出價像素,然後設定價格和顏色。
     *
     * @dev 拋出:繼承自 `bid` 和 `setPrice`。
     *
     * @param tokenId_ 要出價和設定的代幣ID。
     * @param bidPrice_ 出價。
     * @param newPrice_ 要設定的新價格。
     * @param color_ 要設定的顏色。
     */
    function setPixel(
        uint256 tokenId_,
        uint256 bidPrice_,
        uint256 newPrice_,
        uint256 color_
    ) external;

    /**
     * @notice 為像素設定顏色。
     *
     * @dev 存取:只有代幣擁有者或已批准的操作者。
     * @dev 拋出:`Unauthorized` 或 `ERC721: operator query for nonexistent token` 錯誤。
     * @dev 發出:`Color` 事件。
     *
     * @param tokenId_ 要設定的代幣ID。
     * @param color_ 要設定的顏色。
     */
    function setColor(uint256 tokenId_, uint256 color_) external;

    function getColor(uint256 tokenId_) external view returns (uint256 color);

    /**
     * @notice 獲取特定地址擁有的像素。
     * @param owner_ 擁有者地址。
     * @param limit_ 返回像素的限制。
     * @param offset_ 返回像素的偏移量。
     * @return total 像素的總數。
     * @return limit 返回像素的限制。
     * @return offset 返回像素的偏移量。
     * @return pixels 打包的像素。
     * @dev 基於偏移量的分頁
     */
    function getPixelsByOwner(
        address owner_,
        uint256 limit_,
        uint256 offset_
    )
        external
        view
        returns (
            uint256 total,
            uint256 limit,
            uint256 offset,
            ITheSpaceRegistry.Pixel[] memory pixels
        );
    /////////////////////////////
    /// 交易Trading
    //////////////////////////////

    function getPrice(uint256 tokenId_) external view returns (uint256 price);

    /**
     * @notice 設定特定代幣ID的當前價格。首先觸發稅收結算,稅收成功收取後,價格才會成功更新。
     *
     * @dev 存取:只有代幣擁有者或已批准的操作者。
     * @dev 拋出:`Unauthorized` 或 `ERC721: operator query for nonexistent token` 錯誤。
     * @dev 發出:`Price` 事件。
     *
     * @param tokenId_ 要更新的代幣ID。
     * @param price_ 要更新的新價格。
     */
    function setPrice(uint256 tokenId_, uint256 price_) external;

    /**
     * @notice 回傳具有代幣ID的Harberger財產的當前擁有者。
     * @dev 如果代幣不存在,則返回零地址,用戶可以像往常一樣出價代幣。
     * @param tokenId_ 要查詢的代幣ID。
     * @return owner 當前擁有者地址。
     */
    function getOwner(uint256 tokenId_) external view returns (address owner);

    /**
     * @notice 以高於當前價格的出價購買財產。
     * 如果出價高於要價,則只會扣除要價。
     * @dev 在轉移之前為擁有者清除稅收。
     *
     * @dev 拋出:`PriceTooLow` 或 `InvalidTokenId` 錯誤。
     * @dev 發出:`Deal`, `Tax` 事件。
     *
     * @param tokenId_ 被出價的代幣ID。
     * @param price_ 出價。
     */
    function bid(uint256 tokenId_, uint256 price_) external;

    //////////////////////////////
    /// 稅收 & UBI
    //////////////////////////////

    /**
     * @notice 計算代幣的未繳稅款。
     * @param tokenId_ 要查詢的代幣ID。
     * @return amount 需要支付的稅款當前金額。
     */
    function getTax(uint256 tokenId_) external view returns (uint256 amount);

    /**
     * @notice 計算可以收取的稅款金額,並確定是否應該默認代幣。
     * @param tokenId_ 要查詢的代幣ID。
     * @return collectable 考慮餘額和允許值,可以收取的貨幣金額。
     * @return shouldDefault 當前代幣是否應該被默認。
     */
    function evaluateOwnership(uint256 tokenId_) external view returns (uint256 collectable, bool shouldDefault);

    /**
     * @notice 收取代幣的未繳稅款,如有需要則默認它。
     * @dev 任何人都可以觸發此功能。對於開發者團隊來說,可能希望觸發它一段時間,以確保所有代幣都符合其稅收義務。
     *
     * @dev 拋出:`PriceTooLow` 或 `InvalidTokenId` 錯誤。
     * @dev 發出:`Tax` 事件。
     *
     * @param tokenId_ 被結算的代幣ID。
     * @return success 稅收是否已完全收取,且代幣未被默認。
     */
    function settleTax(uint256 tokenId_) external returns (bool success);

    /**
     * @notice 給定代幣的可提取UBI金額。
     * @param tokenId_ 要查詢的代幣ID。
     * @param amount 可收集的UBI金額。
     */
    function ubiAvailable(uint256 tokenId_) external view returns (uint256 amount);

    /**
     * @notice 提取給定代幣的所有UBI。
     *
     * @dev 發出:`UBI` 事件。
     *
     * @param tokenId_ 被提取的代幣ID。
     */
    function withdrawUbi(uint256 tokenId_) external;
    //////////////////////////////
    /// 註冊回調 Registery Backcall
    //////////////////////////////

    /**
     * @notice 在註冊合約中,`safeTransfer` 和 `safeTransferFrom` 之前執行。
     * @dev 收取稅款並設定價格。
     *
     * @dev 存取:只有註冊。
     * @dev 拋出:`Unauthorized` 錯誤。
     *
     * @param tokenId_ 要轉移的代幣ID。
     * @return success 稅收是否已完全收取,且代幣未被默認。
     */
    function _beforeTransferByRegistry(uint256 tokenId_) external returns (bool success);

    /**
     * @notice 由註冊合約獲取代幣URI。
     *
     * @dev 存取:只有註冊。
     * @dev 拋出:`Unauthorized` 或 `TokenNotExists` 錯誤。
     *
     * @param tokenId_ 要轉移的代幣ID。
     * @return uri Base64編碼的URI。
     */
    function _tokenURI(uint256 tokenId_) external view returns (string memory uri);
}

ITheSpaceRegistry 重要data structure
它繼承了IERC721Enumerable,這意味著它包含了ERC-721標準中的所有功能,並添加了可列舉功能。

    //////////////////////////////
    /// Data structure
    //////////////////////////////

    /**
     * Options for global tax configuration.
     * @param taxRate: Tax rate in bps every 1000 blocks
     * @param treasuryShare: Share to treasury in bps.
     * @param mintTax: Tax to mint a token. It should be non-zero to prevent attacker constantly mint, default and mint token again.
     */
    enum ConfigOptions {
        taxRate,
        treasuryShare,
        mintTax
    }

    /**
     * Record of each token.
     * @param price Current price.
     * @param lastTaxCollection Block number of last tax collection.
     * @param ubiWithdrawn Amount of UBI been withdrawn.
     */
    struct TokenRecord {
        uint256 price;
        uint256 lastTaxCollection;
        uint256 ubiWithdrawn;
    }

    /**
     * Global state of tax and treasury.
     * @param accumulatedUBI Total amount of currency allocated for UBI.
     * @param accumulatedTreasury Total amount of currency allocated for treasury.
     * @param treasuryWithdrawn Total amount of treasury been withdrawn.
     */
    struct TreasuryRecord {
        uint256 accumulatedUBI;
        uint256 accumulatedTreasury;
        uint256 treasuryWithdrawn;
    }

 
    struct Pixel {
        uint256 tokenId;
        uint256 price;
        uint256 lastTaxCollection;
        uint256 ubi;
        address owner;
        uint256 color;
    }

https://github.com/anoanoano/NonomosHL/blob/master/contracts/ERC721HarbergerLicense.sol

thisartworkisalwaysonsale

art-steward contract
透過哈伯格稅收模型從當前所有者那裡收取贊助金,並在贊助者無法支付時接管藝術品的管理。
合約的功能包括設定價格、收取贊助金、管理擁有者、維護藝術品的 ERC721 代幣等。
哈伯格稅(COST)模型要求始終將藝術品放在出售狀態,以設定價格,並支付贊助金以維持所有權。
ArtSteward 合約可以控制 ERC721 資產,並處理購買和贊助金的相關作業。

這個智能合約使用了哈伯格稅收模型來管理藝術品的所有權和贊助金的收取,同時保護免受前置攻擊。
合約還允許贊助者存入贊助金、購買藝術品、更改價格以及提取存款等操作。
藝術家可以提取贊助金,而存放的資金可以在需要時提取。

view function

  • patronageOwed():計算從上次收取贊助金到現在應付的贊助金。
  • patronageOwedRange(uint256 _time):計算在指定時間內應付的贊助金。
  • currentCollected():計算從上次收取贊助金到現在應付的贊助金。
  • patronageOwedWithTimestamp():傳回目前應付的贊助金以及當前時間戳記。
  • foreclosed():檢查合約是否處於被清算狀態。
  • depositAbleToWithdraw():計算可以提取的存款金額。
  • foreclosureTime():計算合約清算的預計時間。

actions

  • _collectPatronage():用於確定應付的贊助金金額,並進行相應的操作。
  • buy(uint256 _newPrice, uint256 _currentPrice):購買藝術品,並處理前置攻擊保護和資金分配。
  • depositWei():贊助者存入贊助金。
  • changePrice(uint256 _newPrice):更改藝術品的價格。
  • withdrawDeposit(uint256 _wei):贊助者提取存款。
  • exit():贊助者完全退出合約。
  • withdrawArtistFunds():藝術家提取贊助金。
  • withdrawPullFunds():提取已存放的資金。
  /* internal */
   //用於提取存款
    function _withdrawDeposit(uint256 _wei) internal { 
        // note: can withdraw whole deposit, which puts it in immediate to be foreclosed state.
        require(deposit >= _wei, 'Withdrawing too much');

        deposit = deposit.sub(_wei);
        msg.sender.transfer(_wei); // msg.sender == patron

        _forecloseIfNecessary();
    }
    //檢查是否需要清算合約
    function _forecloseIfNecessary() internal {
        if(deposit == 0) {
            // become steward of artwork (aka foreclose)
            address currentOwner = art.ownerOf(42);
            transferArtworkTo(currentOwner, address(this), 0);
            emit LogForeclosure(currentOwner);
        }
    }
    // 轉移藝術品的所有權。
    function transferArtworkTo(address _currentOwner, address _newOwner, uint256 _newPrice) internal {
        // note: it would also tabulate time held in stewardship by smart contract
        timeHeld[_currentOwner] = timeHeld[_currentOwner].add((timeLastCollected.sub(timeAcquired)));
        
        art.transferFrom(_currentOwner, _newOwner, 42);

        price = _newPrice;
        timeAcquired = now;
        patrons[_newOwner] = true;
    }

Fxhash ticket

fxhash github contracts內有三個與ticket有關的合約

TicketClaimV3.ts / TicketUpdatePriceV3.ts /MintWithTicketV3.ts 前兩者與本次主題較為相關


export interface ITaxationSettings {
  coverage: number
  price: number
}

export type TTicketClaimV3OperationParams = {
  ticketId: number
  amount: number
  taxationSettings: ITaxationSettings
}
// 定義了 TicketUpdatePriceV3Operation class,它繼承自自訂的 ContractOperation 類別。 
此類別用於執行更新門票價格的操作。
export class TicketUpdatePriceV3Operation extends ContractOperation<TTicketUpdatePriceV3OperationParams> {
  contract: ContractAbstraction<Wallet> | null = null

  async prepare() {
    this.contract = await this.manager.getContract(
      FxhashContracts.MINT_TICKETS_V3
    )
  }
  //call() 方法用於實際呼叫智能合約的 update_price 函數,以更新門票價格。
  此方法傳回一個 TransactionWalletOperation 對象,表示交易操作。
  
  async call(): Promise<TransactionWalletOperation> {
    const amount = Math.ceil(this.params.amount)
    return this.contract!.methodsObject.update_price({
      token_id: this.params.ticketId,
      taxation: this.params.taxationSettings,
    }).send({
      amount,
      mutez: true,
    })
  }

  success(): string {
    return `You have successfully updated the ticket pricing settings.`
  }
  or
  
}
//總的來說,這段程式碼的目的是透過 Taquito 與 Tezos 區塊鏈上的智能合約進行互動,執行更新門票價格的操作。 操作的參數包括門票 ID、金額和稅收設定。 成功執行後,返回成功訊息。
export type TMintWithTicketOperationParams = {
  ticketId: number
  token: GenerativeToken
  inputBytes: string
}

/**
 * Mint an unique iteration of a Generative Token
 */
export class MintWithTicketOperation extends ContractOperation<TMintWithTicketOperationParams> {
  contract: ContractAbstraction<Wallet> | null = null

  async prepare() {
    this.contract = await this.manager.getContract(FxhashContracts.ISSUER_V3)
  }

  async call(): Promise<TransactionWalletOperation> {
    return this.contract!.methodsObject.mint_with_ticket({
      issuer_id: this.params.token.id,
      ticket_id: this.params.ticketId,
      input_bytes: this.params.inputBytes,
      recipient: null,
    }).send()
  }

  success(): string {
    return `You have successfully exchanged one ticket for an iteration of "${this.params.token.name}".`
  }
}

上一篇
Day 27 - PCO -1
下一篇
Day 29 - solidity 學習資源整理
系列文
Web3 X 公共財30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言